/**
 * Trabalho 2 
 * Sequencial 1 - Texto wikipedia.txt 
 *
 * GRUPO 9 : Alfredo L. Porfirio
 *           Diego Gomes da Silva
 *           Marcos V. S. Ferreira
 *
 * Compile: g++ -o seq1 seq1.cpp 
 */

// Bibliotecas
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include <sys/time.h>

// O numero maximo que é encontrado o numero primo
#define NMAX 100000

//Ambiente
using namespace std;

// Vetor para calculo dos numeros pi( De 2 até NMAX ); 
int v[NMAX];


// Contadores de palindromos e de primos
int n_pali = 0;
int n_prime = 0;


// Deixa as letras todas maisculas de uma string 
string toUpperCase(string s) {
    for (int i = 0; i < s.size(); i++)
        s[i] = toupper(s[i]);
    return s;
}

// Faz a tabela de primos pelo Crivo Erastótenes 
// (calcula todos os primos de uma vez só até o valor NMAX)
int table_prime() {
    int i, j;
    int raiz;

    raiz = (int) sqrt(NMAX);

    for (i = 2; i < NMAX; i++) v[i] = i;

    for (i = 2; i < raiz; i++) {
        if (v[i] == i) {
            for (j = i + i; j < NMAX; j += i) {
                v[j] = 0; // removendo da lista
            }
        }
    }
}

// Acessa o vetor v para verificar se é primo(acesso direto)
bool is_prime(int value) {
    return (bool)v[value];
}


// Limpa a string de apontuacao
void remove_pontuacion(string& in) {
    for (int i = 0; i < in.length(); i++) {
        // ispunct é uma funcao da ctype.h que detecta se é alguma potuacao ja predefinida  
        if (ispunct(in[i]))
            in[i] = ' '; // troca a pontuacao por espaco em branco
    }
    return;
}

// faz a soma dos valores dos caracteres segundo a tabela ASCII
int sum_char(string& word) {
    int i, out = 0;
    for (i = 0; i < word.size(); i++) out += word[i];
    return out;
}


// verifica se um string é palindromo, utilizando iterators da <string>
bool palindrome(string s) {
    if (equal(s.begin(), s.begin() + s.size() / 2, s.rbegin()))
        return true;
    else
        return false;
}

// Dado uma linha do arquivo (in), quebra em palavras (palavras entre os espacos brancos)
// E verifica se é palindromo ou nao, se for verifica se é primo tambem.
void token(string& in) {
    istringstream iss(in);

    do {
        string sub;
        iss >> sub; // pega a proxima proxima palavra da linha
        // assumindo palidromos com no minimo 3 char
        if (sub.size() > 2) {
            sub = toUpperCase(sub); // tudo caixa alta 
            if (palindrome(sub)) {
                n_pali++;

                int sum = sum_char(sub);
                if (is_prime(sum))
                    n_prime++;
            }
        }
    } while (iss); //ate as as palavras acabarem
}


// Variavel para ajudar a contar o tempo
#define MICRO_PER_SECOND 1000000 


// Funcao principal
int main() {
    // Estruturas pra contar o tempo
    struct timeval start_time;
    struct timeval stop_time;
    float time_diff;

    gettimeofday(&start_time, NULL);

    // faz o calculo dos primos e conta o tempo 
    table_prime();

    gettimeofday(&stop_time, NULL);
    time_diff = (float) (stop_time.tv_sec - start_time.tv_sec);
    time_diff += (stop_time.tv_usec - start_time.tv_usec) / (float) MICRO_PER_SECOND;
    printf("Calculo da Crivo de Erastotenes em %f s\n", time_diff);


    // variavel para pegar as linhas do arquivo que esta em fin
    string line;
    ifstream fin("wikipedia.txt"); // ifstream = padrão ios:in
    // se abrir com sucesso
    if (fin.is_open()) {
        gettimeofday(&start_time, NULL);

        while (!fin.eof()) //enquanto end of file for false continua
        {
            getline(fin, line, '\n'); // pega a linha do arquivo até o '\n' segundo o arquivo
            // remove toda a pontuacao(perceba que podia passar aqui todo o texto para caixa alta, mas seria um custo desnecessario);
            remove_pontuacion(line);
            token(line); //verica na linha a existencia de palindromos 
        }

        // conta o tempo dos palindromos
        gettimeofday(&stop_time, NULL);
        time_diff = (float) (stop_time.tv_sec - start_time.tv_sec);
        time_diff += (stop_time.tv_usec - start_time.tv_usec) / (float) MICRO_PER_SECOND;
        printf("Calculo dos Palindromos em %f s\n", time_diff);

        // fecha o arquivo
        fin.close();
    } else cout << "nao foi possivel abrir o arquivo.." << endl; // mensagem de erro do arquivo

    // imprime as contagens
    cout << "Numero de Palavras Palindromas: " << n_pali << endl;
    cout << "Numero de Primos: " << n_prime << endl;

    return 0;
}